﻿using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using Legend.Object;

namespace Legend.Mesh
{
    public class GroundMesh : IPrimitives<VertexPositionTexture>
    {
        public enum GroundType
        {
            Ground,
            Water,
        }

        private VertexPositionTexture[] vertices;
        private int[] indices;
        private int cursor = 0;

        public PrimitiveType PrimitiveType 
        {
            get { return PrimitiveType.TriangleStrip; }
        }

        public int VertexOffset
        {
            get { return 0; }
        }

        public VertexPositionTexture[] VertexData
        {
            get { return vertices; }
        }

        public int VertexNumber
        {
            get { return vertices.Length; }
        }

        public int[] IndexData
        {
            get { return indices; }
        }

        public int IndexOffset
        {
            get { return 0; }
        }

        public int PrimitiveCount
        {
            get { return VertexNumber - 2; }
        }

        public string TextureName
        {
            get
            {
                return "map.tga";
            }
        }

        public BoundingBox FarestStep
        {
            get
            {
                Vector3 min;
                Vector3 max;

                min.X = vertices[(cursor + vertices.Length - 1) % vertices.Length].Position.X;
                min.Y = vertices[(cursor + vertices.Length - 4) % vertices.Length].Position.Y;
                min.Z = vertices[(cursor + vertices.Length - 4) % vertices.Length].Position.Z;

                max.X = vertices[(cursor + vertices.Length - 4) % vertices.Length].Position.X;
                max.Y = vertices[(cursor + vertices.Length - 1) % vertices.Length].Position.Y;
                max.Z = vertices[(cursor + vertices.Length - 1) % vertices.Length].Position.Z;

                return new BoundingBox(min, max);
            }
        }

        public BoundingBox NearestStep
        {
            get
            {
                Vector3 min;
                Vector3 max;

                min.X = vertices[(cursor + 1) % vertices.Length].Position.X;
                min.Y = vertices[(cursor + 1) % vertices.Length].Position.Y;
                min.Z = vertices[(cursor + 1) % vertices.Length].Position.Z;

                max.X = vertices[(cursor + 2) % vertices.Length].Position.X;
                max.Y = vertices[(cursor + 2) % vertices.Length].Position.Y;
                max.Z = vertices[(cursor + 2) % vertices.Length].Position.Z;

                return new BoundingBox(min, max);
            }
        }

        public GroundMesh(int step)
        {
            vertices = new VertexPositionTexture[step * 2 + 2];
            indices = new int[step * 2 + 2];
            cursor = step * 2 + 2;

            for (int i = 0; i < step * 2 + 2; i += 2)
            {
                vertices[i].Position.X = 400f;
                vertices[i].Position.Y = i * 100f;
                vertices[i].Position.Z = 0;
                vertices[i].TextureCoordinate.X = 1f;
                vertices[i].TextureCoordinate.Y = ((i / 2) % 2 == 0) ? 0f : 1f;


                vertices[i + 1].Position.X = -400f;
                vertices[i + 1].Position.Y = i * 100f;
                vertices[i + 1].Position.Z = 0;
                vertices[i + 1].TextureCoordinate.X = 0f;
                vertices[i + 1].TextureCoordinate.Y = vertices[i].TextureCoordinate.Y;

                indices[i] = i;
                indices[i + 1] = i + 1;

            }
        }

        public void BuildForward(char groundType, out Vector3 position)
        {
            int index = cursor % vertices.Length;
            vertices[index].Position.X = 400f;
            vertices[index].Position.Y = cursor * 100f;
            vertices[index].Position.Z = 0;
            vertices[index].TextureCoordinate.X = 1f;
            vertices[index].TextureCoordinate.Y = ((cursor / 2) % 2 == 0) ? 0f : 1f;

            vertices[index + 1].Position.X = -400f;
            vertices[index + 1].Position.Y = cursor * 100f;
            vertices[index + 1].Position.Z = 0;
            vertices[index + 1].TextureCoordinate.X = 0f;
            vertices[index + 1].TextureCoordinate.Y = vertices[index].TextureCoordinate.Y;

            int sizeDiff = 0;
            int startIndex = 2;

            if (indices.Length > 4 && indices[3] == indices[4])
            {
                sizeDiff -= 2;
                startIndex = 4;
            }

            if (groundType == 'W' || groundType == 'A')
            {
                sizeDiff += 2;
            }

            if (sizeDiff != 0)
            {
                int[] newIndices = new int[indices.Length + sizeDiff];
                for (int i = startIndex; i < indices.Length; ++i)
                {
                    newIndices[i - startIndex] = indices[i];
                }
                indices = newIndices;
            }
            else
            {
                for (int i = startIndex; i < indices.Length; ++i)
                {
                    indices[i - startIndex] = indices[i];
                }
            }

            if (groundType == 'W' || groundType == 'A')
            {
                indices[indices.Length - 4] = (cursor + vertices.Length - 1) % vertices.Length;
                indices[indices.Length - 3] = index;
                indices[indices.Length - 2] = index;
                indices[indices.Length - 1] = (index + 1) % vertices.Length;
            }
            else
            {
                indices[indices.Length - 2] = index;
                indices[indices.Length - 1] = index + 1;
            }

            position.X = 0;
            position.Y = cursor * 100f - 100f;
            position.Z = 0;
            cursor += 2;
        }

        public void BuildBackward()
        {
            VertexPositionTexture[] newVertices = new VertexPositionTexture[vertices.Length + 2];
            int[] newIndices = new int[indices.Length + 2];
            int cursorIndex = cursor % newVertices.Length;

            for (int i = 0; i < cursorIndex; ++i)
            {
                newVertices[i] = vertices[i];
            }

            BoundingBox nearestBox = NearestStep;

            newVertices[cursorIndex].Position.X = nearestBox.Max.X;
            newVertices[cursorIndex].Position.Y = nearestBox.Min.Y - 200f;
            newVertices[cursorIndex].Position.Z = nearestBox.Min.Z;
            newVertices[cursorIndex].TextureCoordinate.X = 1f;
            newVertices[cursorIndex].TextureCoordinate.Y = vertices[(cursor + 2) % vertices.Length].TextureCoordinate.Y;

            newVertices[cursorIndex + 1].Position.X = nearestBox.Min.X;
            newVertices[cursorIndex + 1].Position.Y = nearestBox.Min.Y - 200f;
            newVertices[cursorIndex + 1].Position.Z = nearestBox.Min.Z;
            newVertices[cursorIndex + 1].TextureCoordinate.X = 0f;
            newVertices[cursorIndex + 1].TextureCoordinate.Y = newVertices[cursorIndex].TextureCoordinate.Y;
            
            for (int i = cursorIndex; i < vertices.Length; ++i)
            {
                newVertices[i + 2] = vertices[i];
            }

            for (int i = 0; i < newIndices.Length; ++i)
            {
                newIndices[i] = (cursorIndex + i) % newIndices.Length;
            }

            vertices = newVertices;
            indices = newIndices;
        }
    }
}
